function getControlPoints(x0, y0, x1, y1, x2, y2, t) {
    var d01 = Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2)),
        d12 = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)),
        fa = (t * d01) / (d01 + d12),
        fb = (t * d12) / (d01 + d12),
        p1x = x1 - fa * (x2 - x0),
        p1y = y1 - fa * (y2 - y0),
        p2x = x1 + fb * (x2 - x0),
        p2y = y1 + fb * (y2 - y0);

    return [p1x, p1y, p2x, p2y];
}

function expandPoints(p, tension) {
    var len = p.length,
        allPoints = [],
        n,
        cp;

    for (n = 2; n < len - 2; n += 2) {
        cp = getControlPoints(
            p[n - 2],
            p[n - 1],
            p[n],
            p[n + 1],
            p[n + 2],
            p[n + 3],
            tension
        );
        if (isNaN(cp[0])) {
            continue;
        }
        allPoints.push(cp[0]);
        allPoints.push(cp[1]);
        allPoints.push(p[n]);
        allPoints.push(p[n + 1]);
        allPoints.push(cp[2]);
        allPoints.push(cp[3]);
    }

    return allPoints;
}

class KyLine {
    // tension 张力
    //
    constructor(config) {
        this.config = config;
    }
    points() {
        return this.config.points;
    }
    tension() {
        return this.config.tension;
    }
    closed() {
        return this.config.closed
    }
    bezier() {
        return this.config.bezier
    }
    strokeShape(shape) {
        if (shape.hasStroke()) {
            this._stroke(shape);
        }
    }
    doSplineLine(context) {
        let points = this.points(),
            length = points.length,
            tension = this.tension(),
            closed = this.closed(),
            bezier = this.bezier(),
            tp,
            len,
            n;
        if (!length) {
            throw new Error("绘制样条曲线需要提供点位置");
        }
        context.beginPath();
        context.moveTo(points[0], points[1]);
        console.log(this.config);
        context.lineWidth = this.config.strokeWidth;
        context.strokeStyle = this.config.strokeColor;
        context.lineCap = this.config.lineCap;
        context.lineJoin = this.config.lineJoin;
        // tension 张力 并且提供的点坐标大于两个,曲线tension必须大于0!,否则画实线
        if (tension !== 0 && length > 4&&!bezier) {
            (async () => {
                tp = await this._getTensionPoints();//获取点坐标
                len = tp.length;
                n = closed?0:4;
                if(!closed){
                    context.quadraticCurveTo(tp[0], tp[1], tp[2], tp[3]);
                }
                context.stroke();
                while (n < len - 2) {
                    context.bezierCurveTo(
                        tp[n++],
                        tp[n++],
                        tp[n++],
                        tp[n++],
                        tp[n++],
                        tp[n++]
                    );
                    context.stroke();
                }
                if(!closed){
                    context.quadraticCurveTo(
                        tp[len - 2],
                        tp[len - 1],
                        points[length - 2],
                        points[length - 1]
                    );
                    context.stroke();
                }
            })();
        } else if (bezier) {
            // no tension but bezier
            n = 2;
            console.log('bezier');
            while (n < length) {
                context.bezierCurveTo(
                    points[n++],
                    points[n++],
                    points[n++],
                    points[n++],
                    points[n++],
                    points[n++]
                );
                context.stroke();
            }
        } else {
            // no tension
            for (n = 2; n < length; n += 2) {
                console.log('lineTo');
                context.lineTo(points[n], points[n + 1]);
                context.stroke();
            }
        }
        if(closed){
            context.closePath();
        }else{
            context.closePath();
        }
    }
    _getTensionPoints() {
        return new Promise((reslove, reject) => {
            let data = [];
            console.log("ssssss",this.closed());
            if(this.closed()){
                data = this._getTensionPointsClosed();
            }else{
                data = expandPoints(this.config.points, this.config.tension);
            }
            reslove(data);
        })
    }
    _getTensionPointsClosed(){
        console.log("_getTensionPointsClosed");
        let p = this.points();
        console.log(p);
        let len = p.length;
        console.log(len);
        let tension = this.tension();
        let firstControlPoints = getControlPoints(p[len-2],p[len-1],p[0],p[1],p[2],p[3],tension);
        let lastControlPoints = getControlPoints(p[len-4],p[len-3],p[len-2],p[len-1],p[0],p[1],tension);
        let middle = expandPoints(p,tension);
        let tp = [firstControlPoints[2],firstControlPoints[3]].concat(middle).concat([
            lastControlPoints[0],lastControlPoints[1],p[len-2],p[len-1],
            lastControlPoints[2],
            lastControlPoints[3],
            firstControlPoints[0],
            firstControlPoints[1],
            p[0],
            p[1]
        ]);
        return tp;
    }

}